package com.tl.commonlibrary.storage.filecache;

import android.content.ContentResolver;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.text.TextUtils;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

/**
 * Created by a on 2016/1/7.
 */
public class FileTool {

    private static final int FILE_BUFFER_SIZE = 51200;

    /**
     * 该文件是否存在
     *
     * @param filePath
     * @return
     */
    public static boolean fileIsExist(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return false;
        }
        File f = new File(filePath);
        if (!f.exists()) {
            return false;
        }
        return true;
    }

    /**
     * 创建文件夹
     *
     * @param filePath 文件夹全路径
     * @return
     */
    public static boolean createDirectory(String filePath) {
        if (null == filePath) {
            return false;
        }

        File file = new File(filePath);

        if (file.exists()) {
            return true;
        }

        return file.mkdirs();

    }

    /**
     * 创建文件
     *
     * @param filePath 文件全路径
     * @param fileName 文件名
     * @return
     */
    public static boolean createFile(String filePath, String fileName) {
        if (TextUtils.isEmpty(filePath) || TextUtils.isEmpty(fileName)) {
            return false;
        }

        if (createDirectory(filePath)) {
            File file = new File(filePath, fileName);
            if (!file.exists()) {
                try {
                    return file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                    return false;
                }
            }
        }
        return false;
    }

    /**
     * 删除文件夹或者文件
     */
    public static void delete(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return;
        }
        delete(new File(filePath));
    }

    public static void delete(File file) {
        if (file != null && file.exists()) {
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File tempFile : files) {
                    if (tempFile != null) {
                        if (tempFile.isDirectory()) {
                            delete(tempFile);
                        } else {
                            tempFile.delete();
                        }
                    }
                }
            }
            file.delete();
        }
    }

    /**
     * 获取文件流
     *
     * @param filePath
     * @return
     */
    public static InputStream readFile(String filePath) {
        if (TextUtils.isEmpty(filePath)) {
            return null;
        }
        InputStream is = null;

        try {
            if (fileIsExist(filePath)) {
                File f = new File(filePath);
                is = new FileInputStream(f);
            } else {
                return null;
            }
        } catch (Exception ex) {
//			LogUtil.e("Exception, ex: " + ex.toString());
            return null;
        }
        return is;
    }

    /**
     * 将文件流写入文件
     *
     * @param filePath
     * @param inputStream
     * @return
     */
    public static boolean writeFile(String filePath, InputStream inputStream) {

        if (null == filePath || filePath.length() < 1) {
            return false;
        }

        try {
            File file = new File(filePath);
            if (file.exists()) {
                delete(file);
            }

            String pth = filePath.substring(0, filePath.lastIndexOf("/"));
            boolean ret = createDirectory(pth);
            if (!ret) {
                return false;
            }


            FileOutputStream fileOutputStream = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int c = inputStream.read(buf);
            while (-1 != c) {
                fileOutputStream.write(buf, 0, c);
                c = inputStream.read(buf);
            }
            fileOutputStream.flush();
            fileOutputStream.close();

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return false;

    }

    /**
     * 获取文件大小
     *
     * @param filePath
     * @return
     */
    public static long getFileSize(String filePath) {
        if (null == filePath) {
            return 0;
        }

        File file = new File(filePath);
        if (file == null || !file.exists()) {
            return 0;
        }

        return file.length();
    }

    public static boolean copyFile(ContentResolver cr, String fromPath, String destUri) {
        if (null == cr || null == fromPath || fromPath.length() < 1 || null == destUri || destUri.length() < 1) {
//			LogUtil.e("copyFile Invalid param. cr="+cr+", fromPath="+fromPath+", destUri="+destUri);
            return false;
        }

        InputStream is = null;
        OutputStream os = null;
        try {
            is = new FileInputStream(fromPath);
            if (null == is) {
//				LogUtil.e("Failed to open inputStream: "+fromPath+"->"+destUri);
                return false;
            }

            // check output uri
            String path = null;
            Uri uri = null;

            String lwUri = destUri.toLowerCase();
            if (lwUri.startsWith("content://")) {
                uri = Uri.parse(destUri);
            } else if (lwUri.startsWith("file://")) {
                uri = Uri.parse(destUri);
                path = uri.getPath();
            } else {
                path = destUri;
            }

            // open output
            if (null != path) {
                File fl = new File(path);
                String pth = path.substring(0, path.lastIndexOf("/"));
                File pf = new File(pth);

                if (pf.exists() && !pf.isDirectory()) {
                    pf.delete();
                }

                pf = new File(pth + File.separator);

                if (!pf.exists()) {
                    if (!pf.mkdirs()) {
//	                    LogUtil.e("Can't make dirs, path=" + pth);
                    }
                }

                pf = new File(path);
                delete(pf);

                os = new FileOutputStream(path);
                fl.setLastModified(System.currentTimeMillis());
            } else {
                os = new ParcelFileDescriptor.AutoCloseOutputStream(cr.openFileDescriptor(uri, "w"));
            }

            // copy file
            byte[] dat = new byte[1024];
            int i = is.read(dat);
            while (-1 != i) {
                os.write(dat, 0, i);
                i = is.read(dat);
            }

            is.close();
            is = null;

            os.flush();
            os.close();
            os = null;

            return true;

        }catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != is) {
                try {
                    is.close();
                } catch (Exception ex) {
                }
                ;
            }
            if (null != os) {
                try {
                    os.close();
                } catch (Exception ex) {
                }
            }
        }
        return false;
    }

    /**
     * **********ZIP file operation**************
     */
    public static boolean readZipFile(String zipFileName, StringBuffer crc) {
        try {
            ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFileName));
            ZipEntry entry;
            while ((entry = zis.getNextEntry()) != null) {
                long size = entry.getSize();
                crc.append(entry.getCrc() + ", size: " + size);
            }
            zis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public static byte[] readGZipFile(String zipFileName) {
        if (fileIsExist(zipFileName)) {
//			LogUtil.i("zipFileName: " + zipFileName);
            FileInputStream fin = null;
            ByteArrayOutputStream baos = null;
            try {
                fin = new FileInputStream(zipFileName);
                int size;
                byte[] buffer = new byte[1024];
                baos = new ByteArrayOutputStream();
                while ((size = fin.read(buffer, 0, buffer.length)) != -1) {
                    baos.write(buffer, 0, size);
                }
                return baos.toByteArray();
            }
            catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (fin != null) {
                    try {
                        fin.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
                if (baos != null) {
                    try {
                        baos.flush();
                        baos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }

    public static boolean zipFile(String baseDirName, String fileName, String targerFileName) throws IOException {
        if (baseDirName == null || "".equals(baseDirName)) {
            return false;
        }
        File baseDir = new File(baseDirName);
        if (!baseDir.exists() || !baseDir.isDirectory()) {
            return false;
        }

        String baseDirPath = baseDir.getAbsolutePath();
        File targerFile = new File(targerFileName);
        ZipOutputStream out = new ZipOutputStream(new FileOutputStream(targerFile));
        File file = new File(baseDir, fileName);

        boolean zipResult = false;
        if (file.isFile()) {
            zipResult = fileToZip(baseDirPath, file, out);
        } else {
            zipResult = dirToZip(baseDirPath, file, out);
        }
        out.close();
        return zipResult;
    }

//    public static boolean unZipFile(String fileName, String unZipDir) throws Exception {
//        File f = new File(unZipDir);
//
//        if (!f.exists()) {
//            f.mkdirs();
//        }
//
//        BufferedInputStream is = null;
//        ZipEntry entry;
//        ZipFile zipfile = new ZipFile(fileName);
//        Enumeration<?> enumeration = zipfile.entries();
//        byte data[] = new byte[FILE_BUFFER_SIZE];
////		LogUtil.i("unZipDir: " + unZipDir);
//
//        while (enumeration.hasMoreElements()) {
//            entry = (ZipEntry) enumeration.nextElement();
//
//            if (entry.isDirectory()) {
//                File f1 = new File(unZipDir + "/" + entry.getName());
////				LogUtil.i("entry.isDirectory XXX " + f1.getPath());
//                if (!f1.exists()) {
//                    f1.mkdirs();
//                }
//            } else {
//                is = new BufferedInputStream(zipfile.getInputStream(entry));
//                int count;
//                String name = unZipDir + "/" + entry.getName();
//                RandomAccessFile m_randFile = null;
//                File file = new File(name);
//                if (file.exists()) {
//                    file.delete();
//                }
//
//                file.createNewFile();
//                m_randFile = new RandomAccessFile(file, "rw");
//                int begin = 0;
//
//                while ((count = is.read(data, 0, FILE_BUFFER_SIZE)) != -1) {
//                    try {
//                        m_randFile.seek(begin);
//                    } catch (Exception ex) {
////						LogUtil.e("exception, ex: " + ex.toString());
//                    }
//
//                    m_randFile.write(data, 0, count);
//                    begin = begin + count;
//                }
//
//                file.delete();
//                m_randFile.close();
//                is.close();
//            }
//        }
//
//        return true;
//    }

    private static boolean fileToZip(String baseDirPath, File file, ZipOutputStream out) throws IOException {
        FileInputStream in = null;
        ZipEntry entry = null;

        byte[] buffer = new byte[FILE_BUFFER_SIZE];
        int bytes_read;
        try {
            in = new FileInputStream(file);
            entry = new ZipEntry(getEntryName(baseDirPath, file));
            out.putNextEntry(entry);

            while ((bytes_read = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytes_read);
            }
            out.closeEntry();
            in.close();
        } catch (IOException e) {
//    	   LogUtil.e("Exception, ex: " + e.toString());
            return false;
        } finally {
            if (out != null) {
                out.closeEntry();
            }

            if (in != null) {
                in.close();
            }
        }
        return true;
    }

    private static boolean dirToZip(String baseDirPath, File dir, ZipOutputStream out) throws IOException {
        if (!dir.isDirectory()) {
            return false;
        }

        File[] files = dir.listFiles();
        if (files.length == 0) {
            ZipEntry entry = new ZipEntry(getEntryName(baseDirPath, dir));

            try {
                out.putNextEntry(entry);
                out.closeEntry();
            } catch (IOException e) {
//        	   LogUtil.e("Exception, ex: " + e.toString());
            }
        }

        for (int i = 0; i < files.length; i++) {
            if (files[i].isFile()) {
                fileToZip(baseDirPath, files[i], out);
            } else {
                dirToZip(baseDirPath, files[i], out);
            }
        }
        return true;
    }

    private static String getEntryName(String baseDirPath, File file) {
        if (!baseDirPath.endsWith(File.separator)) {
            baseDirPath = baseDirPath + File.separator;
        }

        String filePath = file.getAbsolutePath();
        if (file.isDirectory()) {
            filePath = filePath + "/";
        }

        int index = filePath.indexOf(baseDirPath);
        return filePath.substring(index + baseDirPath.length());
    }
}
